<template>
    <div class="mb-3">
        <input v-if="tag !== 'textarea'" class="form-control" :class="{ 'is-invalid': inputRef.error }"
            v-model="inputRef.val" @blur="validateInput" v-bind="$attrs">
        <textarea v-else class="form-control" :class="{ 'is-invalid': inputRef.error }" v-model="inputRef.val"
            @blur="validateInput" v-bind="$attrs"></textarea>
        <div v-if="inputRef.error" class="form-text invalid-feedback">{{ inputRef.message }}</div>
    </div>
</template>
<script lang="ts">
import { defineComponent, PropType, reactive, onMounted, watch, computed } from 'vue'
import { emitter } from './ValidateForm.vue'
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
interface RuleProp {
    type: 'required' | 'email' | 'range' | 'custom'
    message?: string
    min?: { length: number, message: string }
    max?: { length: number, message: string }
    validator?: () => boolean
}
export type RulesProp = RuleProp[]
export type tagType = 'input' | 'textarea'
export default defineComponent({
    name: 'ValidateInput',
    props: {
        rules: Array as PropType<RulesProp>,
        modelValue: String,
        tag: {
            type: String as PropType<tagType>,
            default: 'input'
        }
    },
    inheritAttrs: false,
    setup(props, context) {
        const inputRef = reactive({
            val: computed({
                get: () => props.modelValue || '',
                set: val => {
                    context.emit('update:modelValue', val)
                }
            }),
            error: false,
            message: ''
        })

        const validateInput = () => {
            if (props.rules) {
                const allPassed = props.rules.every((rule) => {
                    let passed = true
                    inputRef.message = rule.message || ''
                    switch (rule.type) {
                        case 'required':
                            passed = (inputRef.val.trim() !== '')
                            break
                        case 'email':
                            passed = emailReg.test(inputRef.val)
                            break
                        case 'range':
                            const { min, max } = rule
                            if (min && inputRef.val.trim().length < min.length) {
                                passed = false
                                inputRef.message = min.message
                            } else if (max && inputRef.val.trim().length > max.length) {
                                passed = false
                                inputRef.message = max.message
                            }
                            break
                        case 'custom':
                            passed = rule.validator ? rule.validator() : true
                            break
                        default:
                            break
                    }
                    return passed
                })
                inputRef.error = !allPassed
                return allPassed
            }
            return true
        }
        // 清除输入框内容
        const clearInput = () => {
            inputRef.val = ''
        }
        onMounted(() => {
            emitter.emit('form-item-created', {
                validator: validateInput,
                clearInput: clearInput
            })
        })
        return {
            inputRef,
            validateInput
        }
    }
})
</script>
